package tool

import (
	"MoSkeleton/config/consts"
	"MoSkeleton/framework/core/models"
	"MoSkeleton/framework/utils"
	"MoSkeleton/models/tool"
	"MoSkeleton/services/base"
	tool3 "MoSkeleton/web/pogos/request/tool"
	tool2 "MoSkeleton/web/pogos/response/tool"
	"errors"
	"gorm.io/gorm"
	"reflect"
	"strings"
)

type GenTableService struct {
	base.BaseService
}

func (g *GenTableService) SaveTableByImport(tx *gorm.DB, genTables []*tool.GenTable) (bool, error) {
	result := g.GetDb(tx).Save(genTables)
	return result.RowsAffected > 0, result.Error
}

func (g *GenTableService) DeleteTableByIds(tx *gorm.DB, ids *[]uint64) (bool, error) {
	result := g.GetDb(tx).Where("id in (?)", *ids).Delete(&tool.GenTable{})
	return result.RowsAffected > 0, result.Error
}
func (g *GenTableService) GetAllTableByBizId(bizId uint64) ([]*tool2.GenTableSimpleItemResp, error) {
	itemsResp := make([]*tool2.GenTableSimpleItemResp, 0)
	result := g.GetDb(nil).Table("gen_table").Where("biz_id = ?", bizId).Find(&itemsResp)
	if result.Error != nil && errors.Is(result.Error, gorm.ErrRecordNotFound) {
		return itemsResp, nil
	}
	return itemsResp, result.Error
}

func (g *GenTableService) GetDetailById(id uint64) (*tool2.GenTableDetailResp, error) {
	detailResp, err := g.getDetailAnyById(id)
	return detailResp, err
}

func (g *GenTableService) GetCodeGeneratorById(id uint64) (*tool2.CodeGeneratorResp, error) {
	detailResp := new(tool2.CodeGeneratorResp)
	var err error
	if detailResp.TableDetailResp, err = g.getDetailAnyById(id); err != nil {
		return nil, err
	}
	if detailResp.TableDetailResp.SubTableId > 0 {
		detailResp.SubTable, err = g.GetDetailById(detailResp.TableDetailResp.SubTableId)
	}
	return detailResp, err
}

func (g *GenTableService) GetDetailItemsByBizId(bizId uint64) ([]*tool2.GenTableDetailResp, error) {
	detailResps := make([]*tool2.GenTableDetailResp, 0)
	result := g.GetDb(nil).Table("gen_table").Where("biz_id = ?", bizId).Preload("Columns").Find(&detailResps)
	if result.Error != nil && errors.Is(result.Error, gorm.ErrRecordNotFound) {
		return detailResps, nil
	}
	return detailResps, result.Error
}
func (g *GenTableService) CopyFieldsByTablePrefix(bizId uint64, tablePrefix string, genTable *tool.GenTable) error {
	old := &tool.GenTable{
		BizId:       bizId,
		TablePrefix: tablePrefix,
	}
	result := base.BaseDb.Select("module_name,options ").Where("module_name != ''").Order("updated_at desc").First(old)
	if result.Error != nil && errors.Is(result.Error, gorm.ErrRecordNotFound) {
		return nil
	}
	if result.Error != nil {
		return result.Error
	}
	genTable.ModuleName = old.ModuleName
	if old.Options != "" {
		oldOptionMap := make(map[string]any)
		err := utils.FromJsonString(old.Options, &oldOptionMap)
		if err != nil {
			return nil
		}
		newOptionMap := make(map[string]any)
		newOptionMap[consts.PARENT_MENU_ID] = oldOptionMap[consts.PARENT_MENU_ID]
		newOptionMap[consts.PARENT_MENU_NAME] = oldOptionMap[consts.PARENT_MENU_NAME]
		genTable.Options, err = utils.ToJsonString(newOptionMap)
		return err
	}
	return nil
}

func (g *GenTableService) UpdateCodeGenTable(updateReq *tool3.GenTableUpdateReq) (err error) {
	if utils.MapIsEmpty(updateReq.Params) {
		updateReq.Options = ""
	} else {
		updateReq.Options, err = utils.ToJsonString(updateReq.Params)
		if err != nil {
			return
		}
	}
	genTable := new(tool.GenTable)
	err = genTable.GetById(nil, updateReq.ID, genTable)
	if err != nil {
		return
	}
	err = utils.CopyStruct(genTable, updateReq)
	if err != nil {
		return
	}
	return g.GetDb(nil).Transaction(func(tx *gorm.DB) error {
		result := tx.Save(genTable)
		if result.Error != nil {
			return result.Error
		}
		_, err = genTableColumnService.UpdateColumnsByReq(tx, updateReq.Columns, updateReq.UpdatedBy)
		return err
	})
}

func (g *GenTableService) GetGetTablesByTableNames(tx *gorm.DB, tableNames []string) ([]*tool.GenTable, error) {
	genTables := make([]*tool.GenTable, 0)
	result := g.GetDb(tx).Where("source_table_name in (?)", tableNames).Find(&genTables)
	if result.Error != nil && !errors.Is(result.Error, gorm.ErrRecordNotFound) {
		return nil, result.Error
	}
	return genTables, result.Error
}

func (g *GenTableService) getDetailAnyById(id uint64) (*tool2.GenTableDetailResp, error) {
	detailResp := new(tool2.GenTableDetailResp)
	result := g.GetDb(nil).Table("gen_table").Where("id = ?", id).Preload("Columns").First(&detailResp)
	if result.Error != nil && !errors.Is(result.Error, gorm.ErrRecordNotFound) {
		return nil, result.Error
	}
	if detailResp.Options != "" {
		optionMap := make(map[string]any)
		err := utils.FromJsonString(detailResp.Options, &optionMap)
		if err != nil {
			return nil, err
		}
		detailResp.ParentMenuId = utils.GetStrDef(utils.MapValueString(optionMap, consts.PARENT_MENU_ID), "0")
		detailResp.ParentMenuName = utils.MapValueString(optionMap, consts.PARENT_MENU_NAME)
		detailResp.TreeCode = utils.MapValueString(optionMap, consts.TREE_CODE)
		detailResp.TreeName = utils.MapValueString(optionMap, consts.TREE_NAME)
		detailResp.TreeParentCode = utils.MapValueString(optionMap, consts.TREE_PARENT_CODE)
		detailResp.Options = ""
	} else {
		detailResp.ParentMenuId = "0"
	}
	return detailResp, nil
}

func (g *GenTableService) cutColumnsAsMoModel(columns *[]*tool.GenTableColumn) {
	moModel := models.MoModel{}
	modelType := reflect.TypeOf(moModel)
	for i := 0; i < modelType.NumField(); i++ {
		field := modelType.Field(i)
		for j, column := range *columns {
			if strings.ToLower(column.GoFieldName) == strings.ToLower(field.Name) {
				*columns = append((*columns)[:j], (*columns)[j+1:]...)
				break
			}
		}
	}
}
